home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / less_237.zip / less_237 / lesskey.c < prev    next >
C/C++ Source or Header  |  1994-09-29  |  9KB  |  408 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  *    lesskey [-o output] [input]
  30.  *
  31.  *    Make a .less file.
  32.  *    If no input file is specified, standard input is used.
  33.  *    If no output file is specified, $HOME/.less is used.
  34.  *
  35.  *    The .less file is used to specify (to "less") user-defined
  36.  *    key bindings.  Basically any sequence of 1 to MAX_CMDLEN
  37.  *    keystrokes may be bound to an existing less function.
  38.  *
  39.  *    The input file is an ascii file consisting of a 
  40.  *    sequence of lines of the form:
  41.  *        string <whitespace> action [chars] <newline>
  42.  *
  43.  *    "string" is a sequence of command characters which form
  44.  *        the new user-defined command.  The command
  45.  *        characters may be:
  46.  *        1. The actual character itself.
  47.  *        2. A character preceded by ^ to specify a
  48.  *           control character (e.g. ^X means control-X).
  49.  *        3. A backslash followed by one to three octal digits
  50.  *           to specify a character by its octal value.
  51.  *        4. A backslash followed by b, e, n, r or t
  52.  *           to specify \b, ESC, \n, \r or \t, respectively.
  53.  *        5. Any character (other than those mentioned above) preceded 
  54.  *           by a \ to specify the character itself (characters which
  55.  *           must be preceded by \ include ^, \, and whitespace.
  56.  *    "action" is the name of a "less" action, from the table below.
  57.  *    "chars" is an optional sequence of characters which is treated
  58.  *        as keyboard input after the command is executed.
  59.  *
  60.  *    Blank lines and lines which start with # are ignored.
  61.  *
  62.  *
  63.  *    The output file is a non-ascii file, consisting of
  64.  *    zero or more byte sequences of the form:
  65.  *        string <0> <action>
  66.  *    or
  67.  *        string <0> <action|A_EXTRA> chars <0>
  68.  *
  69.  *    "string" is the command string.
  70.  *    "<0>" is one null byte.
  71.  *    "<action>" is one byte containing the action code (the A_xxx value).
  72.  *    If action is ORed with A_EXTRA, the action byte is followed
  73.  *        by the null-terminated "chars" string.
  74.  */
  75.  
  76. #include "less.h"
  77. #include "cmd.h"
  78.  
  79. char usertable[MAX_USERCMD];
  80.  
  81. struct cmdname
  82. {
  83.     char *cn_name;
  84.     int cn_action;
  85. } cmdnames[] = 
  86. {
  87.     "back-bracket",        A_B_BRACKET,
  88.     "back-line",        A_B_LINE,
  89.     "back-line-force",    A_BF_LINE,
  90.     "back-screen",        A_B_SCREEN,
  91.     "back-scroll",        A_B_SCROLL,
  92.     "back-search",        A_B_SEARCH,
  93.     "back-window",        A_B_WINDOW,
  94.     "debug",        A_DEBUG,
  95.     "display-flag",        A_DISP_OPTION,
  96.     "display-option",    A_DISP_OPTION,
  97.     "end",            A_GOEND,
  98.     "examine",        A_EXAMINE,
  99.     "first-cmd",        A_FIRSTCMD,
  100.     "firstcmd",        A_FIRSTCMD,
  101.     "flush-repaint",    A_FREPAINT,
  102.     "forw-bracket",        A_F_BRACKET,
  103.     "forw-forever",        A_F_FOREVER,
  104.     "forw-line",        A_F_LINE,
  105.     "forw-line-force",    A_FF_LINE,
  106.     "forw-screen",        A_F_SCREEN,
  107.     "forw-scroll",        A_F_SCROLL,
  108.     "forw-search",        A_F_SEARCH,
  109.     "forw-window",        A_F_WINDOW,
  110.     "goto-end",        A_GOEND,
  111.     "goto-line",        A_GOLINE,
  112.     "goto-mark",        A_GOMARK,
  113.     "help",            A_HELP,
  114.     "index-file",        A_INDEX_FILE,
  115.     "invalid",        A_UINVALID,
  116.     "next-file",        A_NEXT_FILE,
  117.     "noaction",        A_NOACTION,
  118.     "percent",        A_PERCENT,
  119.     "pipe",            A_PIPE,
  120.     "prev-file",        A_PREV_FILE,
  121.     "quit",            A_QUIT,
  122.     "repaint",        A_REPAINT,
  123.     "repaint-flush",    A_FREPAINT,
  124.     "repeat-search",    A_AGAIN_SEARCH,
  125.     "repeat-search-all",    A_T_AGAIN_SEARCH,
  126.     "reverse-search",    A_REVERSE_SEARCH,
  127.     "reverse-search-all",    A_T_REVERSE_SEARCH,
  128.     "set-mark",        A_SETMARK,
  129.     "shell",        A_SHELL,
  130.     "status",        A_STAT,
  131.     "toggle-flag",        A_OPT_TOGGLE,
  132.     "toggle-option",    A_OPT_TOGGLE,
  133.     "undo-hilite",        A_UNDO_SEARCH,
  134.     "version",        A_VERSION,
  135.     "visual",        A_VISUAL,
  136.     NULL,            0
  137. };
  138.  
  139. /*
  140.  * Parse one character of a string.
  141.  */
  142. int
  143. tchar(pp)
  144.     char **pp;
  145. {
  146.     register char *p;
  147.     register char ch;
  148.     register int i;
  149.  
  150.     p = *pp;
  151.     switch (*p)
  152.     {
  153.     case '\\':
  154.         ++p;
  155.         switch (*p)
  156.         {
  157.         case '0': case '1': case '2': case '3':
  158.         case '4': case '5': case '6': case '7':
  159.             /*
  160.              * Parse an octal number.
  161.              */
  162.             ch = 0;
  163.             i = 0;
  164.             do
  165.                 ch = 8*ch + (*p - '0');
  166.             while (*++p >= '0' && *p <= '7' && ++i < 3);
  167.             *pp = p;
  168.             return (ch);
  169.         case 'b':
  170.             *pp = p+1;
  171.             return ('\r');
  172.         case 'e':
  173.             *pp = p+1;
  174.             return (ESC);
  175.         case 'n':
  176.             *pp = p+1;
  177.             return ('\n');
  178.         case 'r':
  179.             *pp = p+1;
  180.             return ('\r');
  181.         case 't':
  182.             *pp = p+1;
  183.             return ('\t');
  184.         default:
  185.             /*
  186.              * Backslash followed by any other char 
  187.              * just means that char.
  188.              */
  189.             *pp = p+1;
  190.             return (*p);
  191.         }
  192.     case '^':
  193.         /*
  194.          * Carat means CONTROL.
  195.          */
  196.         *pp = p+2;
  197.         return (CONTROL(p[1]));
  198.     }
  199.     *pp = p+1;
  200.     return (*p);
  201. }
  202.  
  203. usage()
  204. {
  205.     fprintf(stderr, "usage: lesskey [-o output] [input]\n");
  206.     exit(1);
  207. }
  208.  
  209. main(argc, argv)
  210.     int argc;
  211.     char *argv[];
  212. {
  213.     char *p;        /* {{ Can't be register since we use &p }} */
  214.     register char *up;    /* Pointer into usertable */
  215.     FILE *desc;        /* Description file (input) */
  216.     FILE *out;        /* Output file */
  217.     int linenum;        /* Line number in input file */
  218.     char *currcmd;        /* Start of current command string */
  219.     int errors;
  220.     int i, j;
  221.     char line[200];
  222.     char *outfile;
  223.  
  224.     /*
  225.      * Process command line arguments.
  226.      */
  227.     outfile = NULL;
  228.     while (--argc > 0 && **(++argv) == '-')
  229.     {
  230.         switch (argv[0][1])
  231.         {
  232.         case 'o':
  233.             outfile = &argv[0][2];
  234.             if (*outfile == '\0')
  235.             {
  236.                 if (--argc <= 0)
  237.                     usage();
  238.                 outfile = *(++argv);
  239.             }
  240.             break;
  241.         default:
  242.             usage();
  243.         }
  244.     }
  245.     if (argc > 1)
  246.         usage();
  247.  
  248.  
  249.     /*
  250.      * Open the input file, or use standard input if none specified.
  251.      */
  252.     if (argc > 0)
  253.     {
  254.         if ((desc = fopen(*argv, "r")) == NULL)
  255.         {
  256.             perror(*argv);
  257.             exit(1);
  258.         }
  259.     } else
  260.         desc = stdin;
  261.  
  262.     /*
  263.      * Read the input file, one line at a time.
  264.      * Each line consists of a command string,
  265.      * followed by white space, followed by an action name.
  266.      */
  267.     linenum = 0;
  268.     errors = 0;
  269.     up = usertable;
  270.     while (fgets(line, sizeof(line), desc) != NULL)
  271.     {
  272.         ++linenum;
  273.  
  274.         /*
  275.          * Skip leading white space.
  276.          * Replace the final newline with a null byte.
  277.          * Ignore blank lines and comment lines.
  278.          */
  279.         p = line;
  280.         while (*p == ' ' || *p == '\t')
  281.             ++p;
  282.         for (i = 0;  p[i] != '\n' && p[i] != '\0';  i++)
  283.             if (p[i] == '#' && (i == 0 || p[i-1] != '\\'))
  284.                 break;
  285.         p[i] = '\0';
  286.         if (*p == '\0')
  287.             continue;
  288.  
  289.         /*
  290.          * Parse the command string and store it in the usertable.
  291.          */
  292.         currcmd = up;
  293.         do
  294.         {
  295.             if (up >= usertable + MAX_USERCMD)
  296.             {
  297.                 fprintf(stderr, "too many commands, line %d\n",
  298.                     linenum);
  299.                 exit(1);
  300.             }
  301.             if (up >= currcmd + MAX_CMDLEN)
  302.             {
  303.                 fprintf(stderr, "command too long on line %d\n",
  304.                     linenum);
  305.                 errors++;
  306.                 break;
  307.             }
  308.  
  309.             *up++ = tchar(&p);
  310.  
  311.         } while (*p != ' ' && *p != '\t' && *p != '\0');
  312.  
  313.         /*
  314.          * Terminate the command string with a null byte.
  315.          */
  316.         *up++ = '\0';
  317.  
  318.         /*
  319.          * Skip white space between the command string
  320.          * and the action name.
  321.          * Terminate the action name with a null byte if it 
  322.          * is followed by whitespace or a # comment.
  323.          */
  324.         if (*p == '\0')
  325.         {
  326.             fprintf(stderr, "missing whitespace on line %d\n",
  327.                 linenum);
  328.             errors++;
  329.             continue;
  330.         }
  331.         while (*p == ' ' || *p == '\t')
  332.             ++p;
  333.         for (j = 0;  p[j] != ' ' && p[j] != '\t' && 
  334.                  p[j] != '\0';  j++)
  335.             ;
  336.         p[j] = '\0';
  337.  
  338.         /*
  339.          * Parse the action name and store it in the usertable.
  340.          */
  341.         for (i = 0;  cmdnames[i].cn_name != NULL;  i++)
  342.             if (strcmp(cmdnames[i].cn_name, p) == 0)
  343.                 break;
  344.         if (cmdnames[i].cn_name == NULL)
  345.         {
  346.             fprintf(stderr, "unknown action <%s> on line %d\n",
  347.                 p, linenum);
  348.             errors++;
  349.             continue;
  350.         }
  351.         *up++ = cmdnames[i].cn_action;
  352.  
  353.         /*
  354.          * See if an extra string follows the action name.
  355.          */
  356.         for (j = j+1;  p[j] == ' ' || p[j] == '\t';  j++)
  357.             ;
  358.         p += j;
  359.         if (*p != '\0')
  360.         {
  361.             /*
  362.              * OR the special value A_EXTRA into the action byte.
  363.              * Put the extra string after the action byte.
  364.              */
  365.             up[-1] |= A_EXTRA;
  366.             while (*p != '\0')
  367.                 *up++ = tchar(&p);
  368.             *up++ = '\0';
  369.         }
  370.     }
  371.  
  372.     if (errors > 0)
  373.     {
  374.         fprintf(stderr, "%d errors; no output produced\n", errors);
  375.         exit(1);
  376.     }
  377.  
  378.     /*
  379.      * Write the output file.
  380.      * If no output file was specified, use "$HOME/.less"
  381.      */
  382.     if (outfile == NULL)
  383.     {
  384.         p = getenv("HOME");
  385.         if (p == NULL || *p == '\0')
  386.         {
  387.             fprintf(stderr, "cannot find $HOME - using current directory\n");
  388.             strcpy(line, LESSKEYFILE);
  389.         } else
  390.         {
  391.             strcpy(line, p);
  392. #if MSOFTC
  393.             strcat(line, "\\");
  394. #else
  395.             strcat(line, "/");
  396. #endif
  397.             strcat(line, LESSKEYFILE);
  398.         }
  399.         outfile = line;
  400.     }
  401.     if ((out = fopen(outfile, "w")) == NULL)
  402.         perror(outfile);
  403.     else
  404.         fwrite((char *)usertable, 1, up-usertable, out);
  405.     exit(0);
  406. }
  407.  
  408.